// frontend/utils/api-client.js
/**
 * API客户端工具 🌐
 * 
 * 提供优化的API请求功能，包括缓存、重试、批处理和请求合并
 */

import { performanceMonitor } from './performance-monitor';

class APIClient {
  /**
   * 初始化API客户端
   * @param {Object} options - 配置选项
   * @param {string} options.baseURL - API基础URL
   * @param {number} options.timeout - 请求超时时间（毫秒）
   * @param {number} options.retries - 失败重试次数
   * @param {boolean} options.useCache - 是否使用缓存
   * @param {number} options.cacheTTL - 缓存有效期（毫秒）
   */
  constructor(options = {}) {
    this.options = {
      baseURL: '/api',
      timeout: 30000,
      retries: 2,
      useCache: true,
      cacheTTL: 60000, // 1分钟
      ...options
    };
    
    // 请求缓存
    this.cache = new Map();
    
    // 请求队列（用于合并相同请求）
    this.pendingRequests = new Map();
    
    // 批处理队列
    this.batchQueue = new Map();
    
    // 默认请求头
    this.defaultHeaders = {
      'Content-Type': 'application/json',
      'Accept': 'application/json'
    };
    
    // 请求拦截器
    this.requestInterceptors = [];
    
    // 响应拦截器
    this.responseInterceptors = [];
    
    // 添加性能监控拦截器
    this.addResponseInterceptor(response => {
      if (response && response.config) {
        const duration = Date.now() - response.config.startTime;
        performanceMonitor.metrics.apiCalls.push({
          url: response.config.url,
          method: response.config.method,
          duration,
          status: response.status,
          timestamp: new Date().toISOString()
        });
      }
      return response;
    });
  }
  
  /**
   * 添加请求拦截器
   * @param {Function} interceptor - 请求拦截器函数
   * @returns {number} 拦截器ID
   */
  addRequestInterceptor(interceptor) {
    this.requestInterceptors.push(interceptor);
    return this.requestInterceptors.length - 1;
  }
  
  /**
   * 添加响应拦截器
   * @param {Function} interceptor - 响应拦截器函数
   * @returns {number} 拦截器ID
   */
  addResponseInterceptor(interceptor) {
    this.responseInterceptors.push(interceptor);
    return this.responseInterceptors.length - 1;
  }
  
  /**
   * 移除请求拦截器
   * @param {number} id - 拦截器ID
   */
  removeRequestInterceptor(id) {
    this.requestInterceptors[id] = null;
  }
  
  /**
   * 移除响应拦截器
   * @param {number} id - 拦截器ID
   */
  removeResponseInterceptor(id) {
    this.responseInterceptors[id] = null;
  }
  
  /**
   * 应用请求拦截器
   * @param {Object} config - 请求配置
   * @returns {Object} 处理后的请求配置
   */
  applyRequestInterceptors(config) {
    let processedConfig = { ...config };
    
    for (const interceptor of this.requestInterceptors) {
      if (interceptor) {
        processedConfig = interceptor(processedConfig) || processedConfig;
      }
    }
    
    return processedConfig;
  }
  
  /**
   * 应用响应拦截器
   * @param {Object} response - 响应对象
   * @returns {Object} 处理后的响应对象
   */
  applyResponseInterceptors(response) {
    let processedResponse = { ...response };
    
    for (const interceptor of this.responseInterceptors) {
      if (interceptor) {
        processedResponse = interceptor(processedResponse) || processedResponse;
      }
    }
    
    return processedResponse;
  }
  
  /**
   * 生成缓存键
   * @param {Object} config - 请求配置
   * @returns {string} 缓存键
   */
  generateCacheKey(config) {
    const { url, method, params, data } = config;
    return `${method}:${url}:${JSON.stringify(params || {})}:${JSON.stringify(data || {})}`;
  }
  
  /**
   * 从缓存获取响应
   * @param {Object} config - 请求配置
   * @returns {Object|null} 缓存的响应或null
   */
  getFromCache(config) {
    if (!this.options.useCache) return null;
    
    const cacheKey = this.generateCacheKey(config);
    const cachedItem = this.cache.get(cacheKey);
    
    if (cachedItem) {
      const { data, timestamp } = cachedItem;
      const now = Date.now();
      
      // 检查缓存是否过期
      if (now - timestamp < this.options.cacheTTL) {
        return {
          ...data,
          fromCache: true,
          config
        };
      } else {
        // 缓存过期，删除
        this.cache.delete(cacheKey);
      }
    }
    
    return null;
  }
  
  /**
   * 将响应存入缓存
   * @param {Object} config - 请求配置
   * @param {Object} response - 响应对象
   */
  saveToCache(config, response) {
    if (!this.options.useCache || !response) return;
    
    const cacheKey = this.generateCacheKey(config);
    
    this.cache.set(cacheKey, {
      data: response,
      timestamp: Date.now()
    });
  }
  
  /**
   * 清除缓存
   * @param {string} [url] - 可选的URL模式，用于清除特定URL的缓存
   */
  clearCache(url) {
    if (url) {
      // 清除特定URL的缓存
      for (const key of this.cache.keys()) {
        if (key.includes(url)) {
          this.cache.delete(key);
        }
      }
    } else {
      // 清除所有缓存
      this.cache.clear();
    }
  }
  
  /**
   * 发送HTTP请求
   * @param {Object} config - 请求配置
   * @returns {Promise<Object>} 响应Promise
   */
  async request(config) {
    // 合并默认配置
    const finalConfig = {
      ...config,
      headers: {
        ...this.defaultHeaders,
        ...config.headers
      },
      baseURL: config.baseURL || this.options.baseURL,
      timeout: config.timeout || this.options.timeout,
      startTime: Date.now()
    };
    
    // 应用请求拦截器
    const processedConfig = this.applyRequestInterceptors(finalConfig);
    
    // 检查缓存
    const cachedResponse = this.getFromCache(processedConfig);
    if (cachedResponse) {
      return Promise.resolve(this.applyResponseInterceptors(cachedResponse));
    }
    
    // 检查是否有相同的请求正在进行中
    const requestKey = this.generateCacheKey(processedConfig);
    if (this.pendingRequests.has(requestKey)) {
      // 返回现有请求的Promise
      return this.pendingRequests.get(requestKey);
    }
    
    // 创建请求Promise
    const requestPromise = this.executeRequest(processedConfig, 0);
    
    // 将请求添加到待处理队列
    this.pendingRequests.set(requestKey, requestPromise);
    
    // 请求完成后从队列中移除
    requestPromise.finally(() => {
      this.pendingRequests.delete(requestKey);
    });
    
    return requestPromise;
  }
  
  /**
   * 执行HTTP请求（包含重试逻辑）
   * @param {Object} config - 请求配置
   * @param {number} retryCount - 当前重试次数
   * @returns {Promise<Object>} 响应Promise
   */
  async executeRequest(config, retryCount) {
    try {
      // 构建完整URL
      const url = config.baseURL + config.url;
      
      // 准备fetch选项
      const fetchOptions = {
        method: config.method || 'GET',
        headers: config.headers,
        credentials: config.credentials || 'same-origin',
        mode: config.mode || 'cors',
        cache: 'no-cache',
        redirect: config.redirect || 'follow',
        referrerPolicy: config.referrerPolicy || 'no-referrer-when-downgrade',
        signal: config.signal
      };
      
      // 添加请求体
      if (config.data) {
        fetchOptions.body = typeof config.data === 'string' 
          ? config.data 
          : JSON.stringify(config.data);
      }
      
      // 处理URL参数
      let finalUrl = url;
      if (config.params) {
        const searchParams = new URLSearchParams();
        Object.entries(config.params).forEach(([key, value]) => {
          if (value !== undefined && value !== null) {
            searchParams.append(key, value);
          }
        });
        
        const queryString = searchParams.toString();
        if (queryString) {
          finalUrl += (finalUrl.includes('?') ? '&' : '?') + queryString;
        }
      }
      
      // 添加超时处理
      const controller = new AbortController();
      fetchOptions.signal = controller.signal;
      
      const timeoutId = setTimeout(() => {
        controller.abort();
      }, config.timeout);
      
      // 发送请求
      const response = await fetch(finalUrl, fetchOptions);
      
      // 清除超时
      clearTimeout(timeoutId);
      
      // 解析响应
      let data;
      const contentType = response.headers.get('content-type');
      
      if (contentType && contentType.includes('application/json')) {
        data = await response.json();
      } else if (contentType && contentType.includes('text/')) {
        data = await response.text();
      } else {
        data = await response.blob();
      }
      
      // 构建响应对象
      const responseObject = {
        data,
        status: response.status,
        statusText: response.statusText,
        headers: this.parseHeaders(response.headers),
        config,
        request: {
          url: finalUrl,
          method: config.method
        }
      };
      
      // 检查响应状态
      if (!response.ok) {
        throw {
          response: responseObject,
          message: `Request failed with status ${response.status}`
        };
      }
      
      // 缓存成功响应
      this.saveToCache(config, responseObject);
      
      // 应用响应拦截器
      return this.applyResponseInterceptors(responseObject);
      
    } catch (error) {
      // 处理请求错误
      if (retryCount < this.options.retries && this.shouldRetry(error)) {
        // 计算重试延迟（指数退避）
        const delay = Math.min(1000 * Math.pow(2, retryCount), 30000);
        
        // 等待后重试
        await new Promise(resolve => setTimeout(resolve, delay));
        
        // 递归重试
        return this.executeRequest(config, retryCount + 1);
      }
      
      // 超过重试次数或不应重试，抛出错误
      throw this.normalizeError(error, config);
    }
  }
  
  /**
   * 判断是否应该重试请求
   * @param {Object} error - 错误对象
   * @returns {boolean} 是否应该重试
   */
  shouldRetry(error) {
    // 网络错误或服务器错误（5xx）应该重试
    if (!error.response) {
      return true; // 网络错误
    }
    
    if (error.response && error.response.status >= 500) {
      return true; // 服务器错误
    }
    
    // 其他错误不重试
    return false;
  }
  
  /**
   * 规范化错误对象
   * @param {Object} error - 原始错误
   * @param {Object} config - 请求配置
   * @returns {Object} 规范化的错误对象
   */
  normalizeError(error, config) {
    if (error.name === 'AbortError') {
      return {
        message: 'Request timeout',
        config,
        code: 'TIMEOUT',
        isTimeout: true
      };
    }
    
    return {
      message: error.message || 'Request failed',
      response: error.response,
      config,
      code: error.code || 'REQUEST_FAILED'
    };
  }
  
  /**
   * 解析响应头
   * @param {Headers} headers - Fetch API的Headers对象
   * @returns {Object} 解析后的头部对象
   */
  parseHeaders(headers) {
    const result = {};
    headers.forEach((value, key) => {
      result[key] = value;
    });
    return result;
  }
  
  /**
   * 发送GET请求
   * @param {string} url - 请求URL
   * @param {Object} [params] - URL参数
   * @param {Object} [config] - 其他配置
   * @returns {Promise<Object>} 响应Promise
   */
  get(url, params, config = {}) {
    return this.request({
      ...config,
      method: 'GET',
      url,
      params
    });
  }
  
  /**
   * 发送POST请求
   * @param {string} url - 请求URL
   * @param {Object} data - 请求数据
   * @param {Object} [config] - 其他配置
   * @returns {Promise<Object>} 响应Promise
   */
  post(url, data, config = {}) {
    return this.request({
      ...config,
      method: 'POST',
      url,
      data
    });
  }
  
  /**
   * 发送PUT请求
   * @param {string} url - 请求URL
   * @param {Object} data - 请求数据
   * @param {Object} [config] - 其他配置
   * @returns {Promise<Object>} 响应Promise
   */
  put(url, data, config = {}) {
    return this.request({
      ...config,
      method: 'PUT',
      url,
      data
    });
  }
  
  /**
   * 发送PATCH请求
   * @param {string} url - 请求URL
   * @param {Object} data - 请求数据
   * @param {Object} [config] - 其他配置
   * @returns {Promise<Object>} 响应Promise
   */
  patch(url, data, config = {}) {
    return this.request({
      ...config,
      method: 'PATCH',
      url,
      data
    });
  }
  
  /**
   * 发送DELETE请求
   * @param {string} url - 请求URL
   * @param {Object} [config] - 其他配置
   * @returns {Promise<Object>} 响应Promise
   */
  delete(url, config = {}) {
    return this.request({
      ...config,
      method: 'DELETE',
      url
    });
  }
  
  /**
   * 批量发送请求
   * @param {Array<Object>} requests - 请求配置数组
   * @returns {Promise<Array<Object>>} 响应数组Promise
   */
  all(requests) {
    return Promise.all(requests.map(config => this.request(config)));
  }
  
  /**
   * 添加请求到批处理队列
   * @param {string} batchKey - 批处理键
   * @param {Object} config - 请求配置
   * @returns {Promise<Object>} 响应Promise
   */
  addToBatch(batchKey, config) {
    if (!this.batchQueue.has(batchKey)) {
      this.batchQueue.set(batchKey, []);
      
      // 在下一个事件循环中处理批处理
      setTimeout(() => this.processBatch(batchKey), 0);
    }
    
    // 创建延迟Promise
    let resolve, reject;
    const promise = new Promise((res, rej) => {
      resolve = res;
      reject = rej;
    });
    
    // 将请求添加到队列
    this.batchQueue.get(batchKey).push({
      config,
      resolve,
      reject
    });
    
    return promise;
  }
  
  /**
   * 处理批处理队列
   * @param {string} batchKey - 批处理键
   */
  async processBatch(batchKey) {
    const batch = this.batchQueue.get(batchKey);
    this.batchQueue.delete(batchKey);
    
    if (!batch || batch.length === 0) return;
    
    try {
      // 这里可以实现批处理逻辑，例如合并多个请求为一个
      // 简单实现：并行发送所有请求
      const responses = await Promise.all(
        batch.map(item => this.request(item.config).catch(error => ({ error })))
      );
      
      // 分发响应
      responses.forEach((response, index) => {
        if (response.error) {
          batch[index].reject(response.error);
        } else {
          batch[index].resolve(response);
        }
      });
    } catch (error) {
      // 如果批处理失败，拒绝所有请求
      batch.forEach(item => item.reject(error));
    }
  }
}

// 创建默认实例
const apiClient = new APIClient();

// 导出
export default apiClient;
export { APIClient };